use std::str::FromStr;

use apikit::rpc::{ParamAppender, RequestParamSign};
use reqwest::{
    RequestBuilder,
    header::{HeaderName, HeaderValue, InvalidHeaderName, InvalidHeaderValue},
};
use serde::Serialize;
use thiserror::Error;

use crate::param::{__TypeMapper, Header, Path};

impl<T> RequestParamSign<Header<T>> for __TypeMapper {
    type Input = Path<T>;
}

#[derive(Debug, Error)]
pub enum Error {
    #[error(transparent)]
    InvalidHeaderName(#[from] InvalidHeaderName),

    #[error(transparent)]
    InvalidHeaderValue(#[from] InvalidHeaderValue),

    #[error(transparent)]
    SerdeError(#[from] serde_json::Error),
}

impl<T: Serialize> ParamAppender<RequestBuilder> for Header<T> {
    type Error = Error;

    fn append_param(self, mut builder: RequestBuilder) -> Result<RequestBuilder, Self::Error> {
        let value = serde_json::to_value(&self.0)?;
        if let serde_json::Value::Object(obj) = value {
            for (k, v) in obj {
                let s = v.as_str().unwrap_or(&v.to_string()).to_string();
                let header_name = HeaderName::from_str(k.as_str())?;
                let header_value = HeaderValue::from_str(s.as_str())?;
                builder = builder.header(header_name, header_value);
            }
        }
        Ok(builder)
    }
}
